module.exports = function () {
    var express = require('express');
    var socketiojwt = require('socketio-jwt');
    var _ = require('underscore');

    var User = require('./models/user');
    var Question = require('./models/question');
    var options = require('./options');

    var server = require('./app');
    var io = require('socket.io')(server);

    var sockets = [];
    var groups = [];

    io.use(socketiojwt.authorize({
        secret: options.jwtSecret,
        handshake: true
    }));

    io.on('connection', function (socket) {
        var _id = socket.decoded_token.id;
        var _username = socket.decoded_token.username;

        sockets[_username] = socket;

        socket.on('create', function (data, cb) {
            data = data || {};
            var gid = data.gid;
            Question.findById(gid, function (err, question) {
                if (err || !question) {
                    cb('invalid gid', null);
                    return;
                }
                if (groups[gid]) {
                    cb('group already exists', null);
                } else {
                    groups[gid] = [];
                    cb(null, {gid: gid});
                }
            });
        });

        socket.on('join', function (data, cb) {
            data = data || {};
            var gid = data.gid;
            if (!groups[gid]) {
                cb('group not found', null);
                return;
            }
            if (!_.contains(groups[gid], _username)) {
                socket.join(gid);
                groups[gid].push(_username);
            }
            cb(null, {gid: gid, member: groups[gid]});
            socket.to(gid).emit('user joined', {gid: gid, username: _username});
        });

        socket.on('leave', function (data, cb) {
            data = data || {};
            var gid = data.gid;
            if (!groups[gid]) {
                cb('group not found', null);
                return;
            }
            if (_.contains(groups[gid], _username)) {
                socket.leave(gid);
                groups[gid].splice(_.indexOf(groups[gid], _username), 1);
                cb(null, {gid: gid});
                if (_.isEmpty(groups[gid])) {
                    delete groups[gid];
                } else {
                    socket.to(gid).emit('user left', {gid: gid, username: _username});
                }
            } else {
                cb('not group member', null);
            }
        });

        socket.on('gmsg', function (data, cb) {
            data = data || {};
            var gid = data.gid;
            if (!groups[gid]) {
                cb('group not found', null);
                return;
            }
            if (_.contains(groups[gid], _username)) {
                socket.to(gid).emit('gmsg', {gid: gid, username: _username, msg: data.msg});
                cb(null, {gid: gid});
            } else {
                cb('not group member', null);
            }
        });

        socket.on('disconnect', function () {
            var keys = _.keys(groups);
            var len = keys.length;
            for (var i = 0; i < len; ++i) {
                var gid = keys[i];
                if (_.contains(groups[gid], _username)) {
                    groups[gid].splice(_.indexOf(groups[gid], _username), 1);
                    if (_.isEmpty(groups[gid])) {
                        delete groups[gid]
                    } else {
                        socket.to(gid).emit('user left', {gid: gid, username: _username});
                    }
                }
            }
            delete sockets[_username];
        });

        socket.on('sendByU', function (data,cb) {
        	console.log("sendByU"+data);
            data = data || {};
			if (!sockets[data.name]) {
                cb('user offline', null);
                return;
            }
            User.findById(_id, 'friends').populate('friends', '_id username friends').exec(function (err, user) {
                if (err || !user) {
                    cb('internal error', null);
                    return;
                }
                var friends = user.friends;
                var len = friends.length;
                for (var i = 0; i < len; ++i) {
                    if (friends[i].username === data.name) {
                        var lenl = friends[i].friends.length;
                        for (var j = 0; j < lenl; ++j) {
                            if (friends[i].friends[j].toString() === _id) {
                                sockets[data.name].emit('receiveByU', {name: _username, msg: data.msg});
                                cb(null, {name: data.name});
                                return;
                            }
                        }
                        //sockets[data.name].emit('friend request', {username: _username});
                        cb('friend mismatch', null);
                        return;
                    }
                }
                cb('not friend', null);
            });
            
        });

		socket.on('sendByQU', function (data,cb) {
			console.log("sendByQU"+data);
            data = data || {};
			if (!sockets[data.name]) {
                cb('user offline', null);
                return;
            }
            if (realms[_username] !== 'student' || realms[data.name] !== 'teacher') {
                cb('realm mismatch', null);
                return;
            }
			
			Question.findById(data.question, function (err, question) {
				if (err || !question) {
					//socket.emit('err', genErr('sendByQU', data, 'internal error'));
					cb('question invalid', null);
					return;
				}
				sockets[data.name].emit('receiveByQ',{question: data.question, msg: data.msg});
				cb(null, {name: data.name,question: data.question});
			});
        });

		socket.on('sendByQid', function (data,cb) {
			console.log("sendByQid"+data);
            data = data || {};
			if (!sockets[data.name]) {
                cb('user offline', null);
                return;
            }
            if (realms[_username] !== 'teacher' || realms[data.name] !== 'student') {
                cb('realm mismatch', null);
                return;
            }
			Question.findById(data.question, 'creator').populate('creator', '_id username').exec(function (err, question) {
                if (err || !question) {
                    cb('question invalid', null);
                    return;
                }
				sockets[data.username].emit('receiveByQU',{name: _username, question: data.question, msg: data.msg});
				cb(null, {question: data.question});
            });
        });
    });
};